#ifndef GRAPH_HPP
#define GRAPH_HPP
#include <algorithm>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <set>
#include <vector>
// #define IDX_ZERO

namespace tbp {
using time_pair = std::pair<uint32_t, uint32_t>;
class BiGraph {
  // record adj
public:
  /**
   * TODO:改成数组表示，vector相对来说也有性能损失
   */
  std::vector<std::vector<uint32_t>> upper_adj_;
  std::vector<std::vector<uint32_t>> lower_adj_;
  // 记录不同的start time
  std::vector<std::set<uint32_t>> upper_edge_time_set_;

  std::vector<std::set<uint32_t>> upper_edge_time_set_end_;

  std::vector<std::vector<time_pair>> upper_edge_time_;
  std::vector<std::vector<time_pair>> lower_edge_time_;

  // 考虑用Hash或者vector来表示节点序，应该来说vector会更快
  // 同时需要正向记录和反向记录
  std::vector<uint32_t> vertex_order_;

  uint32_t upper_size_ = 0;
  uint32_t lower_size_ = 0;
  uint64_t edge_size_ = 0;

  // ==========================================
  // TODO:
  uint32_t *upper_degree_ = nullptr;
  uint32_t *lower_degree_ = nullptr;
  uint32_t *upper_edges_ = nullptr;
  uint32_t *lower_edges_ = nullptr;
  time_pair *upper_times_ = nullptr;
  time_pair *lower_times_ = nullptr;
  // ==========================================

  void BuildGraph(std::string path);
  std::vector<uint32_t> GetVertexOrder();
  void format();

  inline uint32_t Get_U_Degree(uint32_t v) {
    return this->upper_degree_[v] - this->upper_degree_[v - 1];
  }
  inline uint32_t Get_L_Degree(uint32_t v) {
    return this->lower_degree_[v] - this->lower_degree_[v - 1];
  }
  inline uint32_t *Get_U_Edges(uint32_t v) {
    return &this->upper_edges_[upper_degree_[v - 1]];
  }
  inline uint32_t *Get_L_Edges(uint32_t v) {
    return &this->lower_edges_[lower_degree_[v - 1]];
  }
  inline time_pair *Get_U_Edge_Time(uint32_t v) {
    return &this->upper_times_[upper_degree_[v - 1]];
  }
  inline time_pair *Get_L_Edge_Time(uint32_t v) {
    return &this->lower_times_[lower_degree_[v - 1]];
  }
  inline uint32_t Get_UEdge_Idx(uint32_t v) {
    return this->upper_degree_[v - 1];
  }
  inline uint32_t Get_LEdge_Idx(uint32_t v) {
    return this->lower_degree_[v - 1];
  }

private:
  void compute_vertex_order();
};

} // namespace tbp

#endif